checkout: honor opaque checkouts
authorGiuseppe Scrivano <gscrivan@redhat.com>
Mon, 5 Mar 2018 23:01:14 +0000 (00:01 +0100)
committerAtomic Bot <atomic-devel@projectatomic.io>
Fri, 26 Oct 2018 18:26:51 +0000 (18:26 +0000)
if a file ".wh..wh..opq" is present in a directory, delete anything
from lower layers that is already in that directory.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
Closes: #1486
Approved by: cgwalters

src/libostree/ostree-repo-checkout.c
tests/basic-test.sh

index 5ae799231c772ed3b2da6e0f59501076752347ab..e190a14a38cea282ade3b8112bda6600537ae561 100644 (file)
@@ -35,6 +35,7 @@
 #include "ostree-repo-private.h"
 
 #define WHITEOUT_PREFIX ".wh."
+#define OPAQUE_WHITEOUT_NAME ".wh..wh..opq"
 
 /* Per-checkout call state/caching */
 typedef struct {
@@ -879,6 +880,7 @@ checkout_tree_at_recurse (OstreeRepo                        *self,
                           GError                           **error)
 {
   gboolean did_exist = FALSE;
+  gboolean is_opaque_whiteout = FALSE;
   const gboolean sepolicy_enabled = options->sepolicy && !self->disable_xattrs;
   g_autoptr(GVariant) dirtree = NULL;
   g_autoptr(GVariant) dirmeta = NULL;
@@ -912,6 +914,22 @@ checkout_tree_at_recurse (OstreeRepo                        *self,
         return TRUE; /* Note early return */
     }
 
+  if (options->process_whiteouts)
+    {
+      g_autoptr(GVariant) dir_file_contents = g_variant_get_child_value (dirtree, 0);
+      GVariantIter viter;
+      const char *fname;
+      g_autoptr(GVariant) contents_csum_v = NULL;
+      g_variant_iter_init (&viter, dir_file_contents);
+      while (g_variant_iter_loop (&viter, "(&s@ay)", &fname, &contents_csum_v))
+        {
+          is_opaque_whiteout = (g_str_equal (fname, OPAQUE_WHITEOUT_NAME));
+          if (is_opaque_whiteout)
+            break;
+        }
+      contents_csum_v = NULL; /* iter_loop freed it */
+    }
+
   /* First, make the directory.  Push a new scope in case we end up using
    * setfscreatecon().
    */
@@ -931,6 +949,13 @@ checkout_tree_at_recurse (OstreeRepo                        *self,
           return FALSE;
       }
 
+    /* If it is an opaque whiteout, ensure the destination is empty first. */
+    if (is_opaque_whiteout)
+      {
+        if (!glnx_shutil_rm_rf_at (destination_parent_fd, destination_name, cancellable, error))
+          return FALSE;
+      }
+
     /* Create initially with mode 0700, then chown/chmod only when we're
      * done.  This avoids anyone else being able to operate on partially
      * constructed dirs.
index 3c4823d747c9eb22c1fd3df4207a11d3251b2e0c..de4348c21fa99b3e351b497f4851a4b3c88f6257 100644 (file)
@@ -1034,7 +1034,7 @@ echo "ok test error pre commit/bootid"
 # Whiteouts
 cd ${test_tmpdir}
 mkdir -p overlay/baz/
-if touch overlay/baz/.wh.cow && touch overlay/.wh.deeper; then
+if touch overlay/baz/.wh.cow && touch overlay/.wh.deeper && touch overlay/baz/another/.wh..wh..opq; then
     touch overlay/anewfile
     mkdir overlay/anewdir/
     touch overlay/anewdir/blah
@@ -1050,6 +1050,7 @@ if touch overlay/baz/.wh.cow && touch overlay/.wh.deeper; then
     assert_not_has_dir overlay-co/deeper
     assert_has_file overlay-co/anewdir/blah
     assert_has_file overlay-co/anewfile
+    assert_not_has_file overlay-co/baz/another/y
 
     # And test replacing a directory wholesale with a symlink as well as a regular file
     mkdir overlay